스마트 포인터(Smart Pointer)스마트 포인터를 이용해서 프로그래머의 실수로 메모리 누수(Memory Leak)이 발생하는 것을 방어 할 수 있는
수단이다. 포인터처럼 동작하는 클래스 템플릿(Class Template)이다.
기본적으로 힙 영역에 동적 할당되어 메모리를 해제하기 위해서는 delete 키워드를 사용하면 된다.
스마트 포인터를 사용시 메모리 누수를 효과적으로 방지할 수 있기 때문에 컴퓨터 시스템의 안정성을 높일 수 있다.
Java, C#. Python의 가비지 콜렉터와 유사한 기능을 한다.
일반적으로 new 키워드를 이용해서 기본 포인터가 특정한 메모리 주소를 가리키도록 초기화한 이후,
스마트 포인터에 해당 포인터를 넣어서 사용할 수 있다.
정의된 스마트 포인터가 수명을 다했을 때, 소멸자에서 delete 키워드를 이용해, 할당된 메모리들을 자동으로 해제하는 기능을 수행한다.
스마트 포인터 객체unique_ptr; 하나의 스마트 포인터가 특정한 객체를 처리할 수 있도록 한다.
shared_ptr; 특정한 객체를 참조하는 스마트 포인터가 총 몇개인지를 참조한다.
weak_ptr; 하나 이상의 shared_ptr 인스턴스가 소유하는 객체에 대한 접근을 제공한다.(부가적 역할)
unique_ptrC++에서 하나의 스마트 포인터만이 특정한 객체를 처리하도록 할 때, 사용할 수 있다.
스마트 포인터가 특정한 객체의 소유권을 가지고 있을 때만, 소멸자가 객체를 삭제할 수 있다.
move() // 포인터 소유권 이전
reset() // 메모리 할당 해제
#include <iostream>
using namespace std;
int main(void){
unique_ptr<int> p1(new int(10));
unique_ptr<int> p2;
cout<<"스마트 포인터 1: "<<p1<<'\n';
cout<<"스마트 포인터 2: "<<p2<<'\n';
cout<<"----- 소유권 이전 -----\n";
p2=move(p1);
cout<<"스마트 포인터 1: "<<p1<<'\n';
cout<<"스마트 포인터 2: "<<p2<<'\n';
cout<<"----- 메모리 할당 해제 ------";
p2.reset();
cout<<"스마트 포인터 1: "<<p1<<'\n';
cout<<"스마트 포인터 2: "<<p2<<'\n';
system("pause");
return 0;
}
스마트 포인터 1: 0x100542760
스마트 포인터 2: 0x0
----- 소유권 이전 -----
스마트 포인터 1: 0x0
스마트 포인터 2: 0x100542760
----- 메모리 할당 해제 ------
스마트 포인터 1: 0x0
스마트 포인터 2: 0x0
unieque_ptr을 이용한 객체에 접근포인터로 객체에 접근시 포인터처럼 객체의 데이터를 반환
#include <iostream>
using namespace std;
int main(void){
unique_ptr<int> p1(new int(10));
cout<<*p1<<'\n';
system("pause");
}
#include <iostream>
using namespace std;
int main(void){
int* arr=new int[10];
unique_ptr<int> p1(arr);
for(int i=0;i<10;i++){
arr[i]=i;
}
for(int i=0;i<10;i++){
cout<<arr[i]<<' ';
}
p1.reset();
cout<<'\n';
for(int i=0;i<10;i++){
cout<<arr[i]<<' ';
}
system("pause");
}
shared_ptr하나의 특정한 객체를 참조하는 스마트 포인터의 개수가 몇 개인지 참조한다.
특정한 객체를 새로운 스마트 포인터가 참조할 때마자 참조 횟수(Reference Count)가 1씩 증가하며,
각 스마트 포인터의 수명이 다할 때마다 1씩 감소한다.
참조 횟수가 0이되면 delete 키워드를 이용해서 메모리에서 데이터를 자동으로 할당 해제한다.
use_count() //참조하고 있는 객체의 갯수를 반환
#include <iostream>
using namespace std;
int main(void){
int* arr=new int[10];
arr[7]=100;
shared_ptr<int> p1(arr);
cout<<p1.use_count()<<'\n';
shared_ptr<int> p2(p1);
cout<<p1.use_count()<<'\n';
shared_ptr<int> p3=p2;
cout<<p1.use_count()<<'\n';
p1.reset();
p2.reset();
cout<<"arr[7]: "<<arr[7]<<'\n';
p3.reset();
cout<<p1.use_count()<<'\n';
cout<<"arr[7]: "<<arr[7]<<'\n';
system("pause");
return 0;
}
weak_ptr하나 이상의 shared_ptr 객체가 참조하고 있는 객체에 접근할 수 있다.
하지만 해당 객체의 소유자의 수에는 포함되지 않는 스마트 포인터이다.
일반적으로 서로 상대방을 가르키는 두 개의 shared_ptr가 있다면, 참조 횟수는 0이 될수 없다.
따라서 메모리에서 해제될 수 없다. weak_ptr은 위와 같은 순환 참조(Circular Referance)현상을
제거하기 위한 목적으로 사용할 수 있다.
use_count() // waek_ptr이 포인팅하고 있는 객체 수
lock() // 자신이 가리키고 있는 포인터 반환
#include <iostream>
using namespace std;
int main(void){
int* arr=new int(1);
shared_ptr<int> sp1(arr);
weak_ptr<int> wp=sp1;
cout<<sp1.use_count()<<'\n';
cout<<wp.use_count()<<'\n';
if(true){
shared_ptr<int> sp2=wp.lock();
cout<<sp1.use_count()<<'\n';
cout<<wp.use_count()<<'\n';
}
cout<<sp1.use_count()<<'\n';
cout<<wp.use_count()<<'\n';
system("pause");
return 0;
}